﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Media;

namespace VectorRacer
{
    public class Client
    {
        private ObservableCollection<Player> _players = new ObservableCollection<Player>();
        private Coordinates _mapSize = new Coordinates(40, 40);

        private WriteableBitmap _bitmap;

        public WriteableBitmap Bitmap { get { return _bitmap; } }

        public Client()
        {
            _bitmap = new WriteableBitmap(BitmapFrame.Create(Application.GetResourceStream(new Uri(";component/Untitled.jpg", UriKind.Relative)).Stream));
            /*
            unsafe
            {

                int* buffer = (int*)sth3.BackBuffer;
                int a = *buffer;
                string v = a.ToString("x");
            }*/
            //var image = new System.Windows.Controls.Image() { Source =  "Untitled.jpg" };    

        }

        protected bool CheckIfPixelFree(int x, int y)
        {
            unsafe
            {
                int* buffer = (int*)_bitmap.BackBuffer;
                buffer += x;
                buffer += y * _bitmap.BackBufferStride / 4;

                int color = *buffer;

                byte red = (byte)(color >> 16);
                byte green = (byte)(color >> 8);
                byte blue = (byte)(color >> 0);

                if (red == 0 && green == 0 && blue == 0)
                    return false;
            }

            return true;
        }

        public Point GetCollisionPoint(Coordinates destination)
        {
            return GetCollisionPoint(ActivePlayer, destination);
        }

        public Point GetCollisionPoint(Player player, Coordinates destination)
        {
            return GetCollisionPoint(player.Position.X, player.Position.Y, destination.X, destination.Y);
        }

        /// <summary>
        /// Zwraca punkt kolizji(wspolrzedne pixela kolizji) z banda
        /// </summary>
        /// <param name="x1">The x1.</param>
        /// <param name="y1">The y1.</param>
        /// <param name="x2">The x2.</param>
        /// <param name="y2">The y2.</param>
        /// <returns></returns>
        protected Point GetCollisionPoint(int x1, int y1, int x2, int y2)
        {
            int pStartX = (int)(((double)x1 / MapSize.X) * _bitmap.PixelWidth);
            int pEndX = (int)(((double)x2 / MapSize.X) * _bitmap.PixelWidth);
            int pStartY = (int)(((double)y1 / MapSize.Y) * _bitmap.PixelHeight);
            int pEndY = (int)(((double)y2 / MapSize.Y) * _bitmap.PixelHeight);

            int pDeltaX = Math.Abs(pEndX - pStartX);
            int pDeltaY = Math.Abs(pEndY - pStartY);

            int dx = pEndX > pStartX ? 1 : -1;
            int dy = pEndY > pStartY ? 1 : -1;

            int x = 0;
            int y = 0;

            //search for collision in oX
            while (x < pDeltaX)
            {
                if (!CheckIfPixelFree(x * dx + pStartX, y * dy + pStartY))
                    return new Point(x * dx + pStartX, y * dy + pStartY);

                x++;
                y = x * pDeltaY / pDeltaX;
            }

            //search for collision in oY
            if (pDeltaX == 0)
            {
                while (y < pDeltaY)
                {
                    if (!CheckIfPixelFree(x * dx + pStartX, y * dy + pStartY))
                        return new Point(x * dx + pStartX, y * dy + pStartY);

                    y++;
                }
            }

            return new Point(-1, -1);
        }

        protected bool CheckMoveRange(Coordinates proposedPosition)
        {
            return !(proposedPosition.X < 0 || proposedPosition.Y < 0 || proposedPosition.X > MapSize.X || proposedPosition.Y > MapSize.Y);
        }

        public ChechMoveResult CheckMove(Coordinates proposedPosition)
        {
            return CheckMove(ActivePlayer, proposedPosition);
        }

        public ChechMoveResult CheckMove(Player player, Coordinates proposedPosition)
        {
            ChechMoveResult result;

            if (!CheckMoveRange(proposedPosition))
                return ChechMoveResult.OutOfRange;

            result = player.CheckMove(proposedPosition);
            if (result != ChechMoveResult.Correct)
                return result;

            Point collision = GetCollisionPoint(player.Position.X, player.Position.Y, proposedPosition.X, proposedPosition.Y);

            if (collision.X != -1)
                return ChechMoveResult.Crash;

            return ChechMoveResult.Correct;
        }

        public bool Move(Coordinates proposedPosition)
        {
            return Move(ActivePlayer, proposedPosition);
        }

        public bool Move(Player player, Coordinates proposedPosition)
        {
            if (!CheckMoveRange(proposedPosition))
                return false;

            Point collision = GetCollisionPoint(player, proposedPosition);
            if (collision.X != -1)
            {
                int checkWidth = _bitmap.PixelWidth / _mapSize.X;
                int checkHeight = _bitmap.PixelHeight / _mapSize.Y;

                var possiblePoints = new Point[4];
                var passibleLengths = new int[4];

                possiblePoints[0] = new Point(collision.X - collision.X % checkWidth, collision.Y - collision.Y % checkHeight);
                possiblePoints[1] = new Point(possiblePoints[0].X + checkWidth, possiblePoints[0].Y);
                possiblePoints[2] = new Point(possiblePoints[0].X, possiblePoints[0].Y + checkHeight);
                possiblePoints[3] = new Point(possiblePoints[0].X + checkWidth, possiblePoints[0].Y + checkHeight);

                return false;
            }

            return true;
        }

        protected double GetDistance(Point a, Point b)
        {
            return Math.Sqrt((Math.Pow(a.X - b.X, 2) + Math.Pow(a.Y - b.Y, 2)));
        }

        protected void GetAfterCrashPoint(Player player, Coordinates proposedCordinates, Point crashPoint)
        {
            int checkWidth = _bitmap.PixelWidth / _mapSize.X;
            int checkHeight = _bitmap.PixelHeight / _mapSize.Y;

            int moveWidth = checkWidth * Math.Abs(proposedCordinates.X - player.Position.X);
            int moveHeight = checkHeight * Math.Abs(proposedCordinates.Y - player.Position.Y);

            double x = proposedCordinates.X > player.Position.X ? -1 : 1;
            double y = proposedCordinates.Y > player.Position.Y ? -1 : 1;

            Vector moveVector = new Vector(x * checkWidth, y * checkWidth * moveHeight / moveWidth);

            Point currentPoint = crashPoint;
            var possiblePoints = new Point[4];

            while (true)
            {
                possiblePoints[0] = new Point(currentPoint.X - currentPoint.X % checkWidth, currentPoint.Y - currentPoint.Y % checkHeight);
                possiblePoints[1] = new Point(possiblePoints[0].X + checkWidth, possiblePoints[0].Y);
                possiblePoints[2] = new Point(possiblePoints[0].X, possiblePoints[0].Y + checkHeight);
                possiblePoints[3] = new Point(possiblePoints[0].X + checkWidth, possiblePoints[0].Y + checkHeight);
            }

        }

        public Player ActivePlayer
        {
            get { return Players[0]; }
        }

        public ObservableCollection<Player> Players
        {
            get { return _players; }
            set { _players = value; }
        }

        public Coordinates MapSize
        {
            get { return _mapSize; }
            set { _mapSize = value; }
        }
    }
}
